package model.impl;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.List;

import org.hibernate.HibernateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import DAO.HibernateUtil;
import DAO.ScheduleDAO;
import DAO.TicketDAO;
import DAO.TrainDAO;
import DAO.impl.ScheduleDAOImpl;
import DAO.impl.TicketDAOImpl;
import DAO.impl.TrainDAOImpl;
import DTO.DTOManager;
import DTO.ScheduleDTO;
import DTO.TicketDTO;

/**
 * Class that implements the model.Ticket interface.
 */
public class TicketImpl implements model.Ticket {
	
	private TicketDAO ticketDAO = new TicketDAOImpl();
	private ScheduleDAO scheduleDAO = new ScheduleDAOImpl();
	private TrainDAO trainDAO = new TrainDAOImpl();
	
	private Logger logger = LoggerFactory.getLogger("TicketImpl");
	
	private DTOManager dtoManager = new DTOManager();
	

	/**
	 * This method checks if there an available a ticket in DB which has the same 
	 * DTO implementation of schedule as the given DTO of schedule. If such 
	 * ticket is possible to be created: there are free places on schedule, this
	 * passenger doesn't have ticket for this schedule, and departure time is 
	 * later than 10 minutes after current moment, then it creates suck ticket 
	 * and adds it to the DB.
	 * 
	 * @param scheduleDTO - schedule where it's required to buy ticket
	 * @param passenger	  - passenger which wants to buy ticket
	 * @return			  - DTO of created ticket or null if some of conditions
	 * 						failed.
	 */
	public TicketDTO buyTicket(ScheduleDTO scheduleDTO, Passenger passenger) {
		TicketDTO ticketDTO = null;
		try {
			HibernateUtil.beginTransaction();
			if (passenger != null) {
				Train train = trainDAO.findTrainByTrainNumber(scheduleDTO
						.getTrainNumber());
				Schedule schedule = scheduleDAO
						.findScheduleByScheduleDTO(scheduleDTO);
				if (schedule.getTickets().size() < train.getPlaces()) {
					List<Ticket> allTickets = schedule.getTickets();
					for (int i = 0; i < allTickets.size(); i++) {
						if (allTickets.get(i).getPassenger().getLogin()
								.equals(passenger.getLogin())) {
							ticketDTO = new TicketDTO();
							ticketDTO.setTicketID(-1);
							HibernateUtil.commitTransaction();
							return ticketDTO;
						}
					}
					Calendar currentTime = Calendar.getInstance();
					currentTime.add(Calendar.MINUTE, 10);
					if (schedule.getDateOfDeparture()
							.compareTo(currentTime.getTime()) <= 0) {
						ticketDTO = new TicketDTO();
						ticketDTO.setTicketID(-2);
						HibernateUtil.commitTransaction();
						return ticketDTO;
					}
					Ticket ticket = new Ticket();
					ticket = new Ticket();
					ticket.setPassenger(passenger);
					ticket.setSchedule(schedule);
					ticket.setPrice(BigDecimal.valueOf(500)); 
					this.ticketDAO.save(ticket);
					ticketDTO = this.dtoManager.createTicketDTO(ticket);
				}
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in buy ticket " + e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return ticketDTO;
	}
	
	/**
	 * This method checks if there is a ticket in DB which has the same 
	 * DTO implementation as the given DTO. If it is found in DB, method 
	 * removes it.
	 * 
	 * @param ticketDTO - DTO of train which is required to be sold.
	 * @return			- true if the ticket was sold or false in any other
	 * 					  cases.
	 */
	public boolean sellTicket(TicketDTO ticketDTO) {
		try {
			HibernateUtil.beginTransaction();
			Ticket ticket = this.ticketDAO.findByID(Ticket.class, 
					ticketDTO.getTicketID());
			if (ticket != null) {
				this.ticketDAO.delete(ticket);
				HibernateUtil.commitTransaction();
				return true;
			}
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in sell ticket " 
												+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		return false;
	}

	/**
	 * This method checks if there is ticket in DB which has the same ID as 
	 * the given DTO. If such ticket is found , then it looks for schedule
	 * with which this ticket is associated, if such schedule is found method
	 * creates a DTO from it.
	 * 
	 * @param ticketDTO	- DTO of ticket for which it's required to find schedule
	 * @return			- DTO of created schedule or null if the search failed.
	 */
	public ScheduleDTO viewTickInfo(TicketDTO ticketDTO) {
		Ticket ticket = null;
		try {
			HibernateUtil.beginTransaction();
			ticket = this.ticketDAO.findByID(Ticket.class, 
					ticketDTO.getTicketID());
			HibernateUtil.commitTransaction();
		} catch (HibernateException e) {
			this.logger.error("Error in view ticket info " 
													+ e.getLocalizedMessage());
			HibernateUtil.rollbackTransaction();
		} 
		if (ticket != null) {
			return this.dtoManager.createScheduleDTO((ticket.getSchedule()));	
		} else {
			return null;
		}	
	}
}
